
// 获取元素 根据传入的css选择器得到一个伪数组,可以使用GetEle.prototype的属性和方法
function GetEle(selector) {
    var list = [];

    if (typeof selector === "string") {  // css选择器
        list = document.querySelectorAll(selector);
    } else if (selector instanceof Element) { // 单个元素DOM元素
        list = [selector];  // 将元素放到数组中 [li]
    } else if (selector.length) { // 多个元素DOM元素的集合
        list = selector;  // 
    } else if (typeof selector == "function") {
        // $(document).ready(selector)
    } else {
        list = [...arguments];
    }

    list = Array.from(list);  // 转为真数组 
    Object.setPrototypeOf(list, GetEle.prototype);  // 再改为伪数组

    return list; // [ele,ele,ele,ele]
}

// prototype 原型对象方法  => 所有的实例化对象均可使用
// GetEle.prototype.setText = function (con) {
//     // this => 指向调用此方法的实例化对象  // 伪数组  [li,li,li,li]
//     for (var i = 0; i < this.length; i++) {
//         var ele = this[i];
//         ele.textContent = con;
//     }
// }

// GetEle.prototype.getText = function () {
//     // this => 指向调用此方法的实例化对象  // 伪数组  [li,li,li,li]
//     return this[0].textContent;
// }

// text()  可以获取和设置集合中元素的文本内容
// text(111)  有参数就设置
// text()     没有参数就获取
GetEle.prototype.text = function (con) {
    // this => 指向调用此方法的实例化对象 
    if (arguments.length >= 1) {
        // for (var i = 0; i < this.length; i++) {
        //     var ele = this[i];
        //     ele.textContent = con;
        // }

        this.each(function (ele, index) {
            ele.textContent = con;
        })
        return this;
    } else {
        return this[0].textContent;
    }
}

GetEle.prototype.html = function (con) {
    // this => 指向调用此方法的实例化对象
    if (arguments.length >= 1) {
        // for (var i = 0; i < this.length; i++) {
        //     var ele = this[i];
        //     ele.innerHTML = con;
        // }
        this.each(function (ele, index) {
            ele.innerHTML = con;
        })
        return this;
    } else {
        return this[0].innerHTML;
    }
}

GetEle.prototype.val = function (con) {
    // this => 指向调用此方法的实例化对象
    if (arguments.length >= 1) {
        // for (var i = 0; i < this.length; i++) {
        //     var ele = this[i];
        //     ele.value = con;
        // }

        this.each(function (ele, index) {
            ele.value = con;
        })
        return this;
    } else {
        return this[0].value;
    }
}

GetEle.prototype.hide = function () {
    //  this => 指向调用此方法的实例化对象
    // for (var i = 0; i < this.length; i++) {
    //     var ele = this[i];
    //     ele.style.display = "none";
    // }

    this.each(function (ele, index) {
        ele.style.display = "none";
    })
    return this;
}

GetEle.prototype.show = function () {
    //  this => 指向调用此方法的实例化对象
    // for (var i = 0; i < this.length; i++) {
    //     var ele = this[i];
    //     ele.style.display = "block";
    // }

    this.each(function (ele, index) {
        ele.style.display = "block";
    })
    return this;
}

GetEle.prototype.on = function (type, handerFn) {
    //  this => 指向调用此方法的实例化对象
    // for (var i = 0; i < this.length; i++) {
    //     var ele = this[i];
    //     ele.addEventListener(type, handerFn);
    // }

    this.each(function (ele, index) {
        ele.addEventListener(type, handerFn);
    })
    return this;
}

GetEle.prototype.off = function (type, handerFn) {
    //  this => 指向调用此方法的实例化对象
    // for (var i = 0; i < this.length; i++) {
    //     var ele = this[i];
    //     ele.removeEventListener(type, handerFn);
    // }

    this.each(function (ele, index) {
        ele.removeEventListener(type, handerFn);
    })
    return this;
}

GetEle.prototype.click = function (handerFn) {
    //  this => 指向调用此方法的实例化对象
    this.on("click", handerFn);
    return this;
}

GetEle.prototype.each = function (handerFn) {
    // this -> 调用此方法的实例化对象
    for (var i = 0; i < this.length; i++) {
        var item = this[i];
        var index = i;
        // handerFn(item, index);
        handerFn.call(item, item, index);
    }
    return this;
}


GetEle.prototype.addClass = function (classStr) {
    //  this => 指向调用此方法的实例化对象
    var list = classStr.split(" ");
    this.each(function (ele, index) {
        // ele.classList.add("one","two","three");
        ele.classList.add(...list);
        // ele.classList.add.apply(null, list);
    })
    return this;
}

GetEle.prototype.removeClass = function (classStr) {
    //  this => 指向调用此方法的实例化对象
    // debugger;
    var list = classStr.split(" ");
    this.each(function (ele, index) {
        // ele.classList.remove("one","two","three");
        ele.classList.remove(...list);
        // ele.classList.remove.apply(null, list);
    })
    return this;
}

// hasClass()  判断集合中是否存在某个class名
// 只要集合中有一个存在该class名即可 => 包含
GetEle.prototype.hasClass = function (className) {
    //  this => 指向调用此方法的实例化对象
    var flag = false; //假设不存在
    this.each(function (ele, index) {
        if (ele.classList.contains(className)) {
            flag = true;
        }
    })
    return flag;
}

GetEle.prototype.width = function (val) {
    //  this => 指向调用此方法的实例化对象
    if (arguments.length >= 1) {
        this.each(function (ele, index) {

            // val  
            // 可能有单位  200px 200% 200em 200rem 200pt 200vw 200vh 200vmin 200vmax
            // 也能没有单位 200 

            var unitReg = /^\d+(px|%|em|rem|pt|vw|vh|vmin|vmax)$/;

            if (unitReg.test(val)) {
                ele.style.width = val;
            } else {
                ele.style.width = val + "px";
            }

        })
        return this;
    } else {
        // return this[0].style.width;  // style只能获取行内样式
        return parseFloat(this.getCss("width"));

    }
}
GetEle.prototype.height = function (val) {
    //  this => 指向调用此方法的实例化对象
    if (arguments.length >= 1) {
        this.each(function (ele, index) {

            // val  
            // 可能有单位  200px 200% 200em 200rem 200pt 200vw 200vh 200vmin 200vmax
            // 也能没有单位 200 

            var unitReg = /^\d+(px|%|em|rem|pt|vw|vh|vmin|vmax)$/;

            if (unitReg.test(val)) {
                ele.style.height = val;
            } else {
                ele.style.height = val + "px";
            }

        })
        return this;
    } else {
        // return this[0].style.height;  // style只能获取行内样式
        return parseFloat(this.getCss("height"));

    }
}

GetEle.prototype.getCss = function (cssAttr) {
    //  this => 指向调用此方法的实例化对象
    if (window.getComputedStyle) {
        return window.getComputedStyle(this[0])[cssAttr];
    } else {
        return this[0].currentStyle[cssAttr];
    }
}

// attr()   获取和设置属性节点(标签内的属性)
// attr("class","one")   => ele.setAttribute("class","one")
// attr("class")   => ele.getAttribute("class")
GetEle.prototype.attr = function (key, val) {
    if (arguments.length >= 2) {
        this.each(function (ele, index) {
            ele.setAttribute(key, val);
        })
        return this;
    } else if (arguments.length >= 1) {
        return this[0].getAttribute(key);
    }
}

// prop()   获取和设置元素节点的属性(元素节点 => 对象 => 属性和方法 )
// prop("className","one")   => ele.className = "one"
// prop("className")   => ele.className
GetEle.prototype.prop = function (key, val) {
    if (arguments.length >= 2) {
        this.each(function (ele, index) {
            ele[key] = val;
        })
        return this;
    } else if (arguments.length >= 1) {
        return this[0][key];
    }
}

// css()   获取和设置元素节点的属性(元素节点 => 对象 => 属性和方法 )
// css("width","100px")   => ele.style.width = "100px"
// css("width")           => getComputedStyle(ele)["width"]
GetEle.prototype.css = function (cssKey, cssVal) {
    if (arguments.length >= 2) {
        this.each(function (ele, index) {
            ele.style[cssKey] = cssVal;
        })
    } else if (arguments.length >= 1) {
        if (typeof cssKey === "string") {
            return this.getCss(cssKey);
        } else if (Object.prototype.toString.call(cssKey) === "[object Object]") {
            for (var key in cssKey) {
                var val = cssKey[key];
                this.css(key, val);
            }

        }
    }
    return this;
}

// 链式操作 => 方法的返回值还是同种类型的数据
// "YYYY-MM-DD".replace().replace().replace()

// var s = new Set();
// s.add(1).add(2).add(3)

// eq(index) 返回集合中对应下标的元素形成的实例化对象
// $(".list li").eq(0).css({ background: "red" })
GetEle.prototype.eq = function (index) {
    //  this => 指向调用此方法的实例化对象
    // return this[index]; // 返回对应下标的原生dom元素
    return $(this[index]); // 返回对应下标的元素形成实例化对象
}

// siblings()  集合中每一个被选中的元素的 同级元素形成的集合

// $(".first").siblings().css({ background: "red" })
// $(".first,.last").siblings().css({ background: "red" })

GetEle.prototype.siblings = function (index) {
    //  this => 指向调用此方法的实例化对象
    var list = [];
    this.each(function (ele, index) { // ele => 每一个元素
        var parentEle = ele.parentElement;// 找父元素
        var children = parentEle.children; // 父元素的所有子元素

        // 从所有的子元素中 找到 ele的同级元素
        var subArr = Array.from(children).filter(item => item != ele);
        list = list.concat(subArr);
    })
    list = [...new Set(list)];

    return $(list);
}

// 获取匹配的元素 相对于同级的下标
// $(".last").index();
GetEle.prototype.index = function (index) {
    //  this => 指向调用此方法的实例化对象
    var ele = this[0]; // 默认获取集合中的第一个元素

    var parentEle = ele.parentElement;// 找父元素
    var children = parentEle.children; // 父元素的所有子元素

    // ele 被选中的元素在集合中的下标
    var index = Array.from(children).findIndex(item => item === ele);
    return index;
}








function $(selector) {
    return new GetEle(selector);
}